This project aims at providing a thought-provoking outlook on the evolution of the NBA in the 21st Century.
It takes the form of a Shiny App, with each of the following visualisations and their respective Input Variables
The document is organized in three tabs with a deep-dive on Player Performance - with 3 visualisations and a table - a breakdown of Team Performance - with 3 visualisations and a table - and a final Season Recap Visualisation.
The data necessary for this visualisation was scraped from the NBA.com API, partly inspired from an Owen Phillips blog post adaptation of the {ballr} package (which proposed a function for scraping a particular dataset from the NBA.com API).
Plenty of datasets are accessible from the NBA.com API, which was the main source for the project.
For this specific visualisation, the goal was to visualise shooting volume and shooting efficiency by zone for each NBA player.
The main datasets at the source of the following visualisation are as follows :
{get_shot_data_player(player, season)} get_shot_data_player("Stephen Curry", season = "2020-21") %>%
rmarkdown::paged_table()
{get_subtitles_tbl(player, season)}get_subtitles_tbl("Stephen Curry", season = "2020-21") %>%
rmarkdown::paged_table()
{get_team_logo_from_player(player, season)} & {get_player_picture(player, season)}The visualisation is inspired from Espn’s Kirk Goldsberry’s infamous shot charts, and the code for drawing the court also comes from Owen Phillips’ adaptation of the ballr package.
Instead of the tricky hexbins, I went with a shooting proficiency scatterplot with a size variable associated with volume and a fill variable associated with efficiency. In order to have more flexibility drawing the legends than using the traditional {ggplot2} API, I drew the two legends as separate ggplots, which I then added to the scatterplot using the {patchwork} package.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the player pictures and team logo.
I will have to tweak the size parameter variable of the geom points, as it does not discriminate the variance in volume shooting enough in my view.
This specific instance of the visualisation is the result of the function plot_court(player = "Stephen Curry", season = "2020-21") and shows the shooting performance of Stephen Curry in the 2020-21 NBA Season. As we can see, he was both a prolific and efficient shooter this season.
The data necessary for this visualisation was partly scraped from the NBA.com API and partly scraped from basketball-reference.
The main datasets at the source of the following visualisation are as follows :
{get_mean_ts_pct(season)}get_mean_ts_pct(season = "2020-21")
## [1] 0.572
{get_scoring_rate(season)} For this specific dataset, I scraped the per-possession statistics from the NBA.com API to get the 100 best volume scorers in a specific season, as well as their shooting efficiency.
get_scoring_rate(season = "2020-21") %>%
rmarkdown::paged_table()
In order to speed up the r code, I used the {future} version of the {purrr}package, the {furrr} package.
This visualisation is a mapping of the best scorers in the NBA in terms of volume and efficiency.
In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected player’s name, picture and relevant statistics using HTML and CSS.
This specific instance of the visualisation is the result of the function plot_scoring_rate(team = "San Antonio Spurs", season = "2020-21") and puts forth the best scorers of the 2020-21 NBA Season while highlighting the San Antonio Spurs players.
The data necessary for this visualisation was partly scraped from the NBA.com API and from basketball-reference.
The goal for this visualisation was to provide a ranking of the top 10 best players in each of the main statistical categories.
The main datasets at the source of the following visualisation are as follows :
{get_bpm_join(season)}get_bpm_join(season = "2020-21") %>%
rmarkdown::paged_table()
This visualisation is a ranked bar chart of the 10 best NBA players in a specific statistical category, in a specific season.
In relevant instances (Box Plus-Minus and Rebounding), the offensive and defensive components of the metric are highlighted so as to put forth the statistical particularities of each player.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the player pictures as axis.
In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected player’s name, picture and relevant statistics using HTML and CSS.
This specific instance of the visualisation is the result of the function plot_player_ranking_interactive(variable = "bpm", season = "2020-21") and puts forth the best players of the 2020-21 NBA Season in terms of Box Plus-Minus.
The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.
The goal for this table was to provide a ranking of the top 25 best players in each of the main statistical categories with a context of team performance.
The main datasets at the source of the following visualisation are as follows :
{get_bpm_join(season)}{get_playoff_teams(season)}get_playoff_teams(season = "2019-20")
## [1] "Dallas Mavericks" "Los Angeles Clippers" "Utah Jazz"
## [4] "Los Angeles Lakers" "Milwaukee Bucks" "Miami Heat"
## [7] "Boston Celtics" "Toronto Raptors" "Houston Rockets"
## [10] "Denver Nuggets" "Orlando Magic" "Portland Trail Blazers"
## [13] "Brooklyn Nets" "Oklahoma City Thunder" "Indiana Pacers"
## [16] "Philadelphia 76ers" "League Average"
{get_champion(.season)}get_champion(.season = "2019-20")
## [1] "Los Angeles Lakers"
{get_all_stars(season)}get_all_stars(season = "2019-20") %>%
rmarkdown::paged_table()
{get_award(award, .season)}get_award(award = "mvp") %>%
rmarkdown::paged_table()
This visualisation is a table of the 25 best NBA players in the selected statistical category, in a specific season.
I used the {gt} package to customize the table, but might decide to look into the {reactable} API for this visualisation in my final output, should I prefer an interactive table.
This specific instance of the visualisation is the result of the function plot_players_table(variable = "bpm", season = "2020-21") and puts forth the best players of the 2020-21 NBA Season in terms of Box Plus-Minus.
| Player-oriented Season Overview | 2019-20 | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Ranking of the 25 best players in Box Plus-Minus | |||||||||||||||||||||
Player Position |
PER GAME STATISTICS | SHOOTING ACCURACY | AWARDS | ALL-IN-ONE METRICS | POSTSEASON | ||||||||||||||||
| Points | Assists | Rebounds | Blocks | Steals | 2 Point Shooting | 3 Point Shooting1 | FT Shooting2 | MVP | DPOY3 | All-Star | BPM4 | Offensive BPM4 | Defensive BPM4 | Team | Playoffs | Champion | Finals MVP | ||||
| 1 | Giannis Antetokounmpo Power Forward
|
29.5 | 5.6 | 13.6 | 1.0 | 1.0 | 63.3% | 30.4% | 63.3% |
|
|
★ |
+11.5 | +7.4 | +4.1 | Bucks Milwaukee
|
✓ |
||||
| 2 | James Harden Shooting Guard
|
34.3 | 7.5 | 6.6 | 0.9 | 1.8 | 55.6% | 35.5% | 86.5% | ★ |
+9.6 | +8.1 | +1.6 | Rockets Houston
|
✓ |
||||||
| 3 | Kawhi Leonard Small Forward
|
27.1 | 4.9 | 7.1 | 0.6 | 1.8 | 50.0% | 37.8% | 88.6% | ★ |
+8.9 | +6.5 | +2.4 | Clippers Los Angeles
|
✓ |
||||||
| 4 | LeBron James Point Guard
|
25.3 | 10.2 | 7.8 | 0.5 | 1.2 | 56.5% | 34.8% | 69.3% | ★ |
+8.4 | +6.6 | +1.8 | Lakers Los Angeles
|
✓ |
|
|
||||
| 5 | Luka Doncic Point Guard
|
28.8 | 8.8 | 9.4 | 0.2 | 1.0 | 57.3% | 31.6% | 75.8% | ★ |
+8.4 | +7.4 | +1 | Mavericks Dallas
|
✓ |
||||||
| 6 | Anthony Davis Power Forward
|
26.1 | 3.2 | 9.3 | 2.3 | 1.5 | 54.2% | 33.0% | 84.6% | ★ |
+8 | +5.4 | +2.6 | Lakers Los Angeles
|
✓ |
|
|||||
| 7 | Damian Lillard Point Guard
|
30.0 | 8.0 | 4.3 | 0.3 | 1.1 | 52.9% | 40.1% | 88.8% | ★ |
+7.5 | +8.3 | -0.9 | Blazers Portland Trail
|
✓ |
||||||
| 8 | Nikola Jokic Center
|
19.9 | 7.0 | 9.7 | 0.6 | 1.2 | 58.9% | 31.4% | 81.7% | ★ |
+7.4 | +5.5 | +2 | Nuggets Denver
|
✓ |
||||||
| 9 | Jimmy Butler Small Forward
|
19.9 | 6.0 | 6.7 | 0.6 | 1.8 | 49.1% | 24.4% | 83.4% | ★ |
+5.4 | +4 | +1.5 | Heat Miami
|
✓ |
||||||
| 10 | Paul George Small Forward
|
21.5 | 3.9 | 5.7 | 0.4 | 1.4 | 45.2% | 41.2% | 87.6% | +4.9 | +3.8 | +1.1 | Clippers Los Angeles
|
✓ |
|||||||
| 11 | Joel Embiid Center
|
23.0 | 3.0 | 11.6 | 1.3 | 0.9 | 52.0% | 33.1% | 80.7% | ★ |
+4.7 | +3.7 | +1 | 76ers Philadelphia
|
✓ |
||||||
| 12 | Kemba Walker Point Guard
|
20.4 | 4.8 | 3.9 | 0.5 | 0.9 | 48.0% | 38.1% | 86.4% | ★ |
+4.6 | +4.9 | -0.3 | Celtics Boston
|
✓ |
||||||
| 13 | Chris Paul Point Guard
|
17.6 | 6.7 | 5.0 | 0.2 | 1.6 | 54.8% | 36.5% | 90.7% | ★ |
+4.4 | +3 | +1.4 | Thunder Oklahoma City
|
✓ |
||||||
| 14 | Nikola Vucevic Center
|
19.6 | 3.6 | 10.9 | 0.8 | 0.9 | 53.3% | 33.9% | 78.4% | +4.2 | +3.7 | +0.5 | Magic Orlando
|
✓ |
|||||||
| 15 | Khris Middleton Small Forward
|
20.9 | 4.3 | 6.2 | 0.1 | 0.9 | 54.2% | 41.5% | 91.6% | ★ |
+4.1 | +3.4 | +0.7 | Bucks Milwaukee
|
✓ |
||||||
| 16 | Jayson Tatum Power Forward
|
23.4 | 3.0 | 7.0 | 0.9 | 1.4 | 47.8% | 40.3% | 81.2% | ★ |
+4 | +3.5 | +0.6 | Celtics Boston
|
✓ |
||||||
| 17 | Trae Young Point Guard
|
29.6 | 9.3 | 4.3 | 0.1 | 1.1 | 50.4% | 36.1% | 86.0% | ★ |
+3.9 | +6.2 | -2.3 | Hawks Atlanta
|
|||||||
| 18 | Rudy Gobert Center
|
15.1 | 1.5 | 13.5 | 2.0 | 0.8 | 69.5% | – | 63.0% | ★ |
+3.6 | +1.7 | +1.9 | Jazz Utah
|
✓ |
||||||
| 19 | Ben Simmons Point Guard
|
16.4 | 8.0 | 7.8 | 0.6 | 2.1 | 58.4% | – | 62.1% | ★ |
+3.6 | +1.3 | +2.3 | 76ers Philadelphia
|
✓ |
||||||
| 20 | Bam Adebayo Power Forward
|
15.9 | 5.1 | 10.2 | 1.3 | 1.1 | 56.5% | – | 69.1% | ★ |
+3.4 | +1.4 | +2 | Heat Miami
|
✓ |
||||||
| 21 | Danilo Gallinari Power Forward
|
18.7 | 1.9 | 5.2 | 0.1 | 0.7 | 47.5% | 40.5% | 89.3% | +3.3 | +4.1 | -0.9 | Thunder Oklahoma City
|
✓ |
|||||||
| 22 | Domantas Sabonis Power Forward
|
18.5 | 5.0 | 12.4 | 0.5 | 0.8 | 56.3% | 25.4% | 72.3% | ★ |
+3.2 | +2 | +1.2 | Pacers Indiana
|
✓ |
||||||
| 23 | Kyle Lowry Point Guard
|
19.4 | 7.5 | 5.0 | 0.4 | 1.4 | 51.7% | 35.2% | 85.7% | ★ |
+3.2 | +2.2 | +1 | Raptors Toronto
|
✓ |
||||||
| 24 | Hassan Whiteside Center
|
15.5 | 1.2 | 13.5 | 2.9 | 0.4 | 61.5% | – | 68.6% | +3.2 | +2.5 | +0.7 | Blazers Portland Trail
|
✓ |
|||||||
| 25 | John Collins Power Forward
|
21.6 | 1.5 | 10.1 | 1.6 | 0.8 | 64.3% | 40.1% | 80.0% | +3.1 | +3.7 | -0.6 | Hawks Atlanta
|
||||||||
| Visualisation by Henri Freixe • Sources : Nba.com, Basketball-reference.com, Espn.com | |||||||||||||||||||||
|
1
Shooting Percentage among players shooting at least 0.2 Three point shots per Game
2
Free Throw Shooting
3
Defensive Player of the Year
4
Box Plus Minus estimates a player's overall contribution
|
|||||||||||||||||||||
The data necessary for this table was partly scraped from the NBA.com API and from basketball-reference.
The goal for this plot was to provide an overview of the best teams, both in terms of Offensive and Defense.
The main datasets at the source of the following visualisation are as follows :
{get_team_advanced(season)}get_team_advanced(season = "2020-21") %>%
rmarkdown::paged_table()
{get_champion(.season)}get_champion(.season = "2020-21") #No Champion yet in 2020-21 as the season is not over
## [1] "Milwaukee Bucks"
This visualisation is a mapping of the 30 NBA teams in terms of Offensive and Defensive Efficiency. The better a given team is at Offense and Defense, the higher and to the right its position is within the mapping.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logos.
In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected team logo’s name and relevant statistics using HTML and CSS.
This specific instance of the visualisation is the result of the function plot_players_table(variable = "bpm", season = "2020-21") and showcases teams efficiency in the 2020-21 NBA Season.
The data necessary for this visualisation was partly scraped from the NBA.com API and from basketball-reference.
The goal for this table was to provide an overview of the evolution of Offensive Strategy and Offensive Efficiency in the 2010s.
The main datasets at the source of the following visualisation are as follows :
{get_all_seas_team_shoot_split(start_season, end_season)}get_all_seas_team_shoot_split() %>%
rmarkdown::paged_table()
{bbal_ref_rating(start_season, end_season, team)}bbal_ref_rating() %>%
rmarkdown::paged_table()
This visualisation is a parallel line chart and bar chart of the evolution of average offensive efficiency on the one hand, and of the share of shots taken that are three point shots on the other hand. It turns out that trading off mid-range shots for three point shots correlates nicely with offensive efficiency.
In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the outlying geom points tooltip to add the selected team’s name and relevant statistic using HTML and CSS.
I also used the {patchwork} package to show merge charts in the same visualisation.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logo.
In order to speed up the r code, I used the {future} version of the {purrr}package, the {furrr} package.
There is also a team argument to this function, so as to show the selected team’s offensive efficiency evolution, on top of the League Average and outliers (season-highs and season-lows) on the one hand, and the selected team’s shooting split evolution on the other hand.
This specific instance of the visualisation is the result of the function plot_off_evo_interactive(team = "global") and showcases League Average offensive efficiency and shooting split evolution from 2011-2012 until 2020-2021.
The data necessary for this visualisation was partly scraped from the NBA.com API, from basketball-reference and from hoopshype.com.
The goal for this visualisation was to explore the correlation between Team Performance (represented by Win Percentage) with given variables (roster salary, offensive efficiency or defensive efficiency for example).
The main datasets at the source of the following visualisation are as follows :
{get_team_standings(season)}get_team_standings(season = "2020-21") %>%
rmarkdown::paged_table()
{get_salaries(season)}get_salaries(season = "2020-21") %>%
rmarkdown::paged_table()
{bballref_efficiency_season(season)} & {bballref_def_efficiency_season(season)} bballref_efficiency_season(season = "2020-21") %>%
rmarkdown::paged_table()
bballref_def_efficiency_season(season = "2020-21") %>%
rmarkdown::paged_table()
This visualisation is a bump chart of teams ranked by Win Percentage, and a specific variable (salary, off. efficiency or def. efficiency) in a given season, with a spotlight on the selected team.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logo.
This specific instance of the visualisation is the result of the function plot_bump_chart(season = "2020-21", variable = "salary",team = "Phoenix Suns") and explores the relationship between Win Percentage and Salary in the 2020-21 NBA Season. The Phoenix Suns look like the team that achieved the most from the least amount of salary roster.
The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.
The goal for this table was to highlight the ranking of each team of a given Conference in a given season.
The main datasets at the source of the following visualisation are as follows :
{get_team_standings(season)}& {get_team_advanced_selections(season)} &{get_traditional_stats(season)}get_team_advanced_selections(season = "2019-20") %>%
rmarkdown::paged_table()
{get_playoff_teams(season)}## [1] "Dallas Mavericks" "Los Angeles Clippers" "Utah Jazz"
## [4] "Los Angeles Lakers" "Milwaukee Bucks" "Miami Heat"
## [7] "Boston Celtics" "Toronto Raptors" "Houston Rockets"
## [10] "Denver Nuggets" "Orlando Magic" "Portland Trail Blazers"
## [13] "Brooklyn Nets" "Oklahoma City Thunder" "Indiana Pacers"
## [16] "Philadelphia 76ers" "League Average"
{get_champion(season)}## [1] "Los Angeles Lakers"
{get_all_stars(season)}get_all_stars(season = "2019-20") %>%
rmarkdown::paged_table()
This visualisation is a table ranking of the NBA teams in terms of Win Percentage, in a given conference, in a given season.
I used the {gt} package to customize the table, but might decide to look into the {reactable} API for this visualisation in my final output, should I prefer an interactive table.
This specific instance of the visualisation is the result of the function plot_teams_table("2019-20", conf = "West") and gives thought-provoking information about teams from the Western Conference in the 2019-20 NBA Season.
| Season Overview Western Conference | 2019-20 | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Top 8 teams in each Conference to qualify for the playoffs | ||||||||||||
Team Record |
TEAM RESULTS | ROSTER STANDOUTS | POSTSEASON | |||||||||
| Win Percentage | Offensive Efficiency1 | Defensive Efficiency1 | Net Rating | All-Stars2 | Leading Scorer | Playoffs | Champion | |||||
| 1 | ↑+9 |
Lakers Los Angeles 52-19
|
73.2% | 111.7 | 106.1 | +5.6 | ★★ |
Davis 26.1 pts per game
|
✓ |
|
||
| 2 | ↑+6 |
Clippers Los Angeles 49-23
|
68.1% | 113.3 | 106.9 | +6.3 | ★ |
Leonard 27.1 pts per game
|
✓ |
|||
| 3 | ↓-1 |
Nuggets Denver 46-27
|
63.0% | 112.6 | 110.4 | +2.2 | ★ |
Jokic 19.9 pts per game
|
✓ |
|||
| 4 | ⁃ |
Rockets Houston 44-28
|
61.1% | 112.5 | 109.8 | +2.7 | ★★ |
Harden 34.3 pts per game
|
✓ |
|||
| 5 | ↑+1 |
Thunder Oklahoma City 44-28
|
61.1% | 110.1 | 108.1 | +2.1 | ★ |
Gilgeous-Alexander 19 pts per game
|
✓ |
|||
| 6 | ↓-1 |
Jazz Utah 44-28
|
61.1% | 111.8 | 109.3 | +2.5 | ★★ |
Mitchell 24 pts per game
|
✓ |
|||
| 7 | ↑+7 |
Mavericks Dallas 43-32
|
57.3% | 115.9 | 111.2 | +4.8 | ★ |
Doncic 28.8 pts per game
|
✓ |
|||
| 8 | ↓-5 |
Blazers Portland Trail 35-39
|
47.3% | 113.2 | 114.3 | -1.1 | ★ |
Lillard 30 pts per game
|
✓ |
|||
| 9 | ↑+3 |
Grizzlies Memphis 34-39
|
46.6% | 108.7 | 109.7 | -1 | Morant 17.8 pts per game
|
|||||
| 10 | ↑+5 |
Suns Phoenix 34-39
|
46.6% | 111.3 | 110.8 | +0.5 | ★ |
Booker 26.6 pts per game
|
||||
| 11 | ↓-4 |
Spurs San Antonio 32-39
|
45.1% | 111.7 | 112.6 | -0.9 | DeRozan 22.1 pts per game
|
|||||
| 12 | ↓-3 |
Kings Sacramento 31-41
|
43.1% | 109.5 | 111.4 | -1.9 | Fox 21.1 pts per game
|
|||||
| 13 | ⁃ |
Pelicans New Orleans 30-42
|
41.7% | 110.5 | 111.8 | -1.3 | ★ |
Ingram 23.8 pts per game
|
||||
| 14 | ↓-3 |
Timberwolves Minnesota 19-45
|
29.7% | 107.6 | 111.6 | -4 | Russell 23.1 pts per game
|
|||||
| 15 | ↓-14 |
Warriors Golden State 15-50
|
23.1% | 104.4 | 113.0 | -8.6 | Wiggins 21.8 pts per game
|
|||||
| Visualisation by Henri Freixe • Sources : Nba.com, Basketball-reference.com, Basketball.realgm.com,Espn.com | ||||||||||||
|
1
Efficiency corresponds to the number of points scored / allowed every 100 possessions
2
Number of players to participate in the 2019-20 NBA All-Star Game
|
||||||||||||
The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.
The goal for this table was to provide an Overview of the main events of the selected NBA Season, looking into the NBA Finals, the NBA All-Star Game and the winners of the main NBA Awards.
The main datasets at the source of the following visualisation are as follows :
{get_finals_stats(season)}get_finals_stats(season = "2018-19") %>%
rmarkdown::paged_table()
{get_award_stats(award, .season)}## # A tibble: 1 x 6
## player_name team pts reb ast award
## <chr> <chr> <dbl> <dbl> <dbl> <chr>
## 1 Giannis Antetokounmpo MIL 27.7 12.5 5.9 mvp
{get_all_stars(season)}get_all_stars(season = "2018-19") %>%
rmarkdown::paged_table()
{get_traditional_stats(season)}get_traditional_stats(season = "2018-19") %>%
rmarkdown::paged_table()
This visualisation regroups three different visualisations and aims at providing a visual overview of a given NBA Season. The three combined visualisations are a scatterplotted lollipop plot that highlights the outcome of the NBA Finals, a text plot providing statistical insights about the recipients of the main NBA Awards and an interactive facetted scatterplot about the NBA All-Stars.
In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the All-Stars geom points tooltip to add the selected player’s team name and relevant statistic using HTML and CSS.
In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logos and player pictures.
The {patchwork} package was used to combine the three visualisations.
In order to speed up the r code, I used the {future} package to run the three plotting functions in parallel.
This specific instance of the visualisation is the result of the function plot_season_recap(season = "2020-21") and provides a deep-dive into the 2020-21 NBA Season.